//
// Created by 原帅 on 2022/10/9.
//

#include "Ree.h"
#include "sys/epoll.h"
#include "RLog.h"
#include "errno.h"
#include "string.h"

#define REE_EVENT_MAX_SIZE 16

#define REE_LINUX_TIMER_FD_FLAG 0x100000000

Ree& Ree::Inst() {
    static Ree ree;
    return ree;
}

Ree::Ree() {
    reefd = epoll_create1(0);
    if (reefd == -1) {
        RLogErr("reefd=%d,error is %s", reefd, strerror(errno))
    }
}

int Ree::addResponder(int fd, ReeProcType type, ReeProcIF *procIf) {
    struct epoll_event event = {0};

    event.data.u64 = fd & 0xffffffff;

    switch (type) {
        case READ_FD:
            event.events = EPOLLIN|EPOLLET;
            break;
        case WRITE_FD:
            event.events = EPOLLOUT|EPOLLET;
            break;
        case TIMER_FD:
            event.data.u64 |=REE_LINUX_TIMER_FD_FLAG;
            event.events = EPOLLIN|EPOLLET;
            break;
        default:
            RLogErr("unknow type:%d",type)
            return -1;
    }
    epoll_ctl(reefd, EPOLL_CTL_ADD, fd, &event);

    if (mapReeProcs.count(fd)){
        std::map<ReeProcType,ReeProcIF*> &mapTypeProc = mapReeProcs.at(fd);
        if (mapTypeProc.count(type)) {
            return 0;
        }else {
            mapTypeProc.insert(std::pair<ReeProcType,ReeProcIF*>(type,procIf));
        }
    } else {
        std::map<ReeProcType,ReeProcIF*> mapTypeProc;
        mapTypeProc.insert(std::pair<ReeProcType,ReeProcIF*>(type,procIf));
        mapReeProcs.insert(std::pair<int,std::map<ReeProcType,ReeProcIF*>>(fd,mapTypeProc));
    }
    return 0;
}

int Ree::processEvent() {
    struct epoll_event events[REE_EVENT_MAX_SIZE] = {0};
    int iRet = epoll_wait(reefd, events ,REE_EVENT_MAX_SIZE, this->msec);
    if (iRet>0)
    {
        for (int i = 0; i < iRet && i<REE_EVENT_MAX_SIZE; ++i) {
            int fd = (int) (events[i].data.u64 & 0xffffffff);
            RLogErr("fd:%d",fd)
            if (mapReeProcs.count(fd)==0) {
                continue;
            }
            std::map<ReeProcType,ReeProcIF*> &mapProc = mapReeProcs.at(fd);
            if ((&mapProc) == NULL) continue;
            else
            {
                if (events[i].events & EPOLLERR)
                {
                    //todo 关闭fd；
                    for (int j = FD_START+1; j < FD_END; ++j) {
                        if (mapProc.count((ReeProcType)j))
                        {
                            mapProc.at((ReeProcType)j)->eventFail(fd,FD_ERROR);
                        }
                    }
                }
                else
                {
                    if (events[i].events & EPOLLIN)
                    {
                        if (REE_LINUX_TIMER_FD_FLAG & events[i].data.u64)
                        {
                            if (mapProc.count(TIMER_FD)) {
                                if (mapProc.at(TIMER_FD) != nullptr)
                                {
                                    mapProc.at(TIMER_FD)->eventProcess(fd,TIMER_FD);
                                }
                            }
                        }
                        else
                        {
                            if (mapProc.count(READ_FD)) {
                                if (mapProc.at(READ_FD) != nullptr)
                                {
                                    mapProc.at(READ_FD)->eventProcess(fd,READ_FD);
                                }
                            }
                        }
                    }
                    if (events[i].events & EPOLLOUT)
                    {
                        if (mapProc.count(WRITE_FD)) {
                            if (mapProc.at(WRITE_FD) != nullptr)
                            {
                                mapProc.at(WRITE_FD)->eventProcess(fd,WRITE_FD);
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}
